﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;

namespace Microsoft.AspNetCore.Builder
{
    /// <summary>
    /// BootstrapAdminAuthorization 认证服务扩展类
    /// </summary>
    public static class BootstrapAdminAuthorizationServiceCollectionExtensions
    {
        /// <summary>
        /// 添加 BootstrapAdmin 认证授权服务，内部调用 AddAuthentication
        /// </summary>
        /// <param name="services">服务容器集合</param>
        /// <param name="configuration">IConfiguration 实例</param>
        /// <param name="configureOptions">BootstrapAdminAuthenticationOptions 配置回调方法</param>
        /// <param name="configureCookies">CookieAuthenticationOptions 配置回调方法</param>
        /// <returns>IServiceCollection 服务容器集合</returns>
        public static AuthenticationBuilder AddBootstrapAdminAuthentication(this IServiceCollection services, IConfiguration configuration, Action<BootstrapAdminAuthenticationOptions> configureOptions = null, Action<CookieAuthenticationOptions> configureCookies = null)
        {
            BootstrapAdminAuthenticationOptions options = null;
            // load meta data from config
            if (configuration != null)
            {
                options = configuration.GetOption(() => new BootstrapAdminAuthenticationOptions());
                options.KeyPath = options.KeyPath.GetOSPlatformPath();
            }
            else options = new BootstrapAdminAuthenticationOptions();

            // config BootstrapAdminOptions
            configureOptions?.Invoke(options);
            return AddAuthentication(services, options, configureCookies, configuration?.GetValue("AppId", "0"));
        }

        private static AuthenticationBuilder AddAuthentication(IServiceCollection services, BootstrapAdminAuthenticationOptions options, Action<CookieAuthenticationOptions> configure = null, string appId = "0")
        {
            // set sso
            var dataProtectionBuilder = services.AddDataProtection(op => op.ApplicationDiscriminator = options.ApplicationDiscriminator)
                .SetApplicationName(options.ApplicationAppName)
                .PersistKeysToFileSystem(new DirectoryInfo(options.KeyPath));
            if (!string.IsNullOrEmpty(options.AuthHost)) dataProtectionBuilder.DisableAutomaticKeyGeneration();

            // Authentication && Cookie
            return services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(op =>
            {
                if (!string.IsNullOrEmpty(options.CookiePath)) op.Cookie.Path = options.CookiePath;
                if (!string.IsNullOrEmpty(options.CookieDomain)) op.Cookie.Domain = options.CookieDomain;
                if (!string.IsNullOrEmpty(options.AuthHost)) op.RebuildRedirectUri(options.AuthHost, appId);
                configure?.Invoke(op);
            });
        }

        /// <summary>
        /// 通过指定 Section 名称 获得配置项类实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="configuration"></param>
        /// <param name="valueFactory">默认值</param>
        /// <returns></returns>
        internal static T GetOption<T>(this IConfiguration configuration, Func<T> valueFactory = null) where T : class
        {
            T ret = default;
            var providerType = typeof(T);
            var section = configuration.GetSection(providerType.Name);
            if (!section.Exists()) section = configuration.GetSection(providerType.FullName);
            if (section.Exists()) ret = section.Get<T>();
            if (ret == default && valueFactory != null) ret = valueFactory.Invoke();
            return ret;
        }
    }
}
